API’s

O que são API’s?

Definição

  • API é a sigla para Application Programming Interface.

  • É uma interface de comunicação que um sistema oferece para que outros sistemas acessem suas funções, dados, serviços e recursos.

  • Possibilitam utilizar funções de um aplicativo dentro de outro, facilitando o trabalho dos desenvolvedores.

  • Permitem o acesso a dados, sem a necessidade de raspagem de superfície (scraping) ou coleta manual.

Tipos de API

API’s privadas

São internas de uma empresa e são usadas apenas para conectar sistemas e dados dentro da empresa.

API’s públicas

São abertas ao público e podem ser usadas por qualquer pessoa.

Pode ou não haver alguma autorização e/ou custo associado a esses tipos de APIs.

API’s de parceiros

Acessíveis apenas por desenvolvedores externos autorizados, em nome de empresas parceiras.

Como funcionam?

Visão geral

  • As APIs funcionam através de um protocolo, um conjunto de instruções, padrões e regras que definem como os sistemas devem se comunicar.

  • Elas estabelecem métodos de requisição, formatos de dados a serem recebidos ou retornados, autenticação e autorização de acesso, entre outros aspectos técnicos.

  • Quando um software utiliza uma API, ele envia uma requisição seguindo as diretrizes estabelecidas pela interface, e em resposta recebe os dados ou realiza as ações desejadas.

Etapas

  1. Uma requisição é enviada ao sistema que disponibiliza uma API (servidor) por um cliente (que pode ser um navegador, um aplicativo móvel ou outro servidor). Geralmente segue o protocolo HTTP (Hypertext Transfer Protocol).

  2. O servidor faz o processamento da requisição, que pode envolver uma consulta a uma base de dados ou acesso a outras funcionalidades.

  3. O servidor envia uma resposta ao cliente. Geralmente inclui um código de status, indicativo de sucesso ou falha na requisição, e os dados solicitados.

Métodos de requisição HTTP

Os principais métodos de requisição são:

  • get: requisição para obter, visualizar ou extrair dados;

  • post: requisição para criar ou enviar novos dados;

  • put: requisição para editar ou atualizar dados;

  • delete: requisição para remover dados.

Códigos de Status HTTP

Códigos de status mais comuns:

  • 1xx (Informacional): Requisição recebida, processo em andamento.

  • 2xx (Exitoso): Requisição recebida com sucesso e aceita.

  • 3xx (Redirecionamento): É necessário tomar alguma medida para completar a requisição.

  • 4xx (Erro de Cliente): A requisição apresenta problemas de sintaxe ou não pôde ser completada por algum motivo. (401, 404)

  • 5xx (Erro de Servidor): O servidor falhou em completar uma requisição válida.

Requisições e chaves de acesso

  • É comum que alguns sistemas exijam o uso de chaves para limitar e controlar a quantidade de requisições de acesso.

  • Essa medida visa a segurança do próprio sistema, garantindo a sua disponibilidade e evitando por exemplo ataques de negação de serviço (DoS).

Requisições e chaves de acesso

  • Além de ajudar a detectar atividades suspeitas, as chaves de acesso também servem para identificar, monitorar e registrar quem consome a API, a fim de obter insights a respeito dos padrões de uso do serviço e aprimorá-lo.

  • Alguns sistemas monetizam o consumo das API’s.

  • Ainda assim, alguns sistemas permitem que sejam feitas requisições keyless.

Endpoints

  • Endpoints são funções ou recursos da API que, dado sua estrutura hierárquica (aninhada, ou em árvore), podem ser acessadas diretamente pelo sistema cliente.

  • Para acessar um endpoint específico dentro de uma API, basta utilizarmos o URL (Uniform Resource Locator) principal da API seguido do caminho correspondente a esse endpoint.

Endpoints

Placeholders

É comum utilizarmos chaves {} como placeholders ao nos referirmos a endpoints.

Parâmetros de consulta

Podemos, ainda utilizar parâmetros simples de consulta para filtrar os resultados de uma requisição. Ex.:

/usuarios?sexo=masculino

JSON

JSON vs. XML

JSON vs. CSV

Exemplos de consumo de API usando R

Vejamos alguns exemplos de como interagir com APIs diferentes utilizando linguagem R.

PokéAPI (Keyless)

if (!require("httr", character.only = TRUE)) {
  install.packages("httr")}
if (!require("jsonlite", character.only = TRUE)) {
  install.packages("jsonlite")}

library(httr)
library(jsonlite)

#Construir URL
 
pokemon_base <- "https://pokeapi.co/api/v2/pokemon/"

pokemon_endpoint <- ""

pokemon_url <- base::paste0(pokemon_base, pokemon_endpoint)

pokemon_url
[1] "https://pokeapi.co/api/v2/pokemon/"

Requisição (API call)

pokemon_call <- httr::GET(pokemon_url)

Retorna uma lista! Nesse caso, com 10 elementos, sendo os de interesse: “url”, “status_code” e “content”.

Visualizar a resposta da API

Para termos uma visão geral resumida do objeto, podemos rodar:

pokemon_call
Response [https://pokeapi.co/api/v2/pokemon/]
  Date: 2024-06-24 02:30
  Status: 200
  Content-Type: application/json; charset=utf-8
  Size: 1.42 kB

Vamos tentar dar uma olhada no conteúdo retornado:

pokemon_call$content
   [1] 7b 22 63 6f 75 6e 74 22 3a 31 33 30 32 2c 22 6e 65 78 74 22 3a 22 68 74
  [25] 74 70 73 3a 2f 2f 70 6f 6b 65 61 70 69 2e 63 6f 2f 61 70 69 2f 76 32 2f
  [49] 70 6f 6b 65 6d 6f 6e 2f 3f 6f 66 66 73 65 74 3d 32 30 26 6c 69 6d 69 74
  [73] 3d 32 30 22 2c 22 70 72 65 76 69 6f 75 73 22 3a 6e 75 6c 6c 2c 22 72 65
  [97] 73 75 6c 74 73 22 3a 5b 7b 22 6e 61 6d 65 22 3a 22 62 75 6c 62 61 73 61
 [121] 75 72 22 2c 22 75 72 6c 22 3a 22 68 74 74 70 73 3a 2f 2f 70 6f 6b 65 61
 [145] 70 69 2e 63 6f 2f 61 70 69 2f 76 32 2f 70 6f 6b 65 6d 6f 6e 2f 31 2f 22
 [169] 7d 2c 7b 22 6e 61 6d 65 22 3a 22 69 76 79 73 61 75 72 22 2c 22 75 72 6c
 [193] 22 3a 22 68 74 74 70 73 3a 2f 2f 70 6f 6b 65 61 70 69 2e 63 6f 2f 61 70
 [217] 69 2f 76 32 2f 70 6f 6b 65 6d 6f 6e 2f 32 2f 22 7d 2c 7b 22 6e 61 6d 65
 [241] 22 3a 22 76 65 6e 75 73 61 75 72 22 2c 22 75 72 6c 22 3a 22 68 74 74 70
 [265] 73 3a 2f 2f 70 6f 6b 65 61 70 69 2e 63 6f 2f 61 70 69 2f 76 32 2f 70 6f
 [289] 6b 65 6d 6f 6e 2f 33 2f 22 7d 2c 7b 22 6e 61 6d 65 22 3a 22 63 68 61 72
 [313] 6d 61 6e 64 65 72 22 2c 22 75 72 6c 22 3a 22 68 74 74 70 73 3a 2f 2f 70
 [337] 6f 6b 65 61 70 69 2e 63 6f 2f 61 70 69 2f 76 32 2f 70 6f 6b 65 6d 6f 6e
 [361] 2f 34 2f 22 7d 2c 7b 22 6e 61 6d 65 22 3a 22 63 68 61 72 6d 65 6c 65 6f
 [385] 6e 22 2c 22 75 72 6c 22 3a 22 68 74 74 70 73 3a 2f 2f 70 6f 6b 65 61 70
 [409] 69 2e 63 6f 2f 61 70 69 2f 76 32 2f 70 6f 6b 65 6d 6f 6e 2f 35 2f 22 7d
 [433] 2c 7b 22 6e 61 6d 65 22 3a 22 63 68 61 72 69 7a 61 72 64 22 2c 22 75 72
 [457] 6c 22 3a 22 68 74 74 70 73 3a 2f 2f 70 6f 6b 65 61 70 69 2e 63 6f 2f 61
 [481] 70 69 2f 76 32 2f 70 6f 6b 65 6d 6f 6e 2f 36 2f 22 7d 2c 7b 22 6e 61 6d
 [505] 65 22 3a 22 73 71 75 69 72 74 6c 65 22 2c 22 75 72 6c 22 3a 22 68 74 74
 [529] 70 73 3a 2f 2f 70 6f 6b 65 61 70 69 2e 63 6f 2f 61 70 69 2f 76 32 2f 70
 [553] 6f 6b 65 6d 6f 6e 2f 37 2f 22 7d 2c 7b 22 6e 61 6d 65 22 3a 22 77 61 72
 [577] 74 6f 72 74 6c 65 22 2c 22 75 72 6c 22 3a 22 68 74 74 70 73 3a 2f 2f 70
 [601] 6f 6b 65 61 70 69 2e 63 6f 2f 61 70 69 2f 76 32 2f 70 6f 6b 65 6d 6f 6e
 [625] 2f 38 2f 22 7d 2c 7b 22 6e 61 6d 65 22 3a 22 62 6c 61 73 74 6f 69 73 65
 [649] 22 2c 22 75 72 6c 22 3a 22 68 74 74 70 73 3a 2f 2f 70 6f 6b 65 61 70 69
 [673] 2e 63 6f 2f 61 70 69 2f 76 32 2f 70 6f 6b 65 6d 6f 6e 2f 39 2f 22 7d 2c
 [697] 7b 22 6e 61 6d 65 22 3a 22 63 61 74 65 72 70 69 65 22 2c 22 75 72 6c 22
 [721] 3a 22 68 74 74 70 73 3a 2f 2f 70 6f 6b 65 61 70 69 2e 63 6f 2f 61 70 69
 [745] 2f 76 32 2f 70 6f 6b 65 6d 6f 6e 2f 31 30 2f 22 7d 2c 7b 22 6e 61 6d 65
 [769] 22 3a 22 6d 65 74 61 70 6f 64 22 2c 22 75 72 6c 22 3a 22 68 74 74 70 73
 [793] 3a 2f 2f 70 6f 6b 65 61 70 69 2e 63 6f 2f 61 70 69 2f 76 32 2f 70 6f 6b
 [817] 65 6d 6f 6e 2f 31 31 2f 22 7d 2c 7b 22 6e 61 6d 65 22 3a 22 62 75 74 74
 [841] 65 72 66 72 65 65 22 2c 22 75 72 6c 22 3a 22 68 74 74 70 73 3a 2f 2f 70
 [865] 6f 6b 65 61 70 69 2e 63 6f 2f 61 70 69 2f 76 32 2f 70 6f 6b 65 6d 6f 6e
 [889] 2f 31 32 2f 22 7d 2c 7b 22 6e 61 6d 65 22 3a 22 77 65 65 64 6c 65 22 2c
 [913] 22 75 72 6c 22 3a 22 68 74 74 70 73 3a 2f 2f 70 6f 6b 65 61 70 69 2e 63
 [937] 6f 2f 61 70 69 2f 76 32 2f 70 6f 6b 65 6d 6f 6e 2f 31 33 2f 22 7d 2c 7b
 [961] 22 6e 61 6d 65 22 3a 22 6b 61 6b 75 6e 61 22 2c 22 75 72 6c 22 3a 22 68
 [985] 74 74 70 73 3a 2f 2f 70 6f 6b 65 61 70 69 2e 63 6f 2f 61 70 69 2f 76 32
[1009] 2f 70 6f 6b 65 6d 6f 6e 2f 31 34 2f 22 7d 2c 7b 22 6e 61 6d 65 22 3a 22
[1033] 62 65 65 64 72 69 6c 6c 22 2c 22 75 72 6c 22 3a 22 68 74 74 70 73 3a 2f
[1057] 2f 70 6f 6b 65 61 70 69 2e 63 6f 2f 61 70 69 2f 76 32 2f 70 6f 6b 65 6d
[1081] 6f 6e 2f 31 35 2f 22 7d 2c 7b 22 6e 61 6d 65 22 3a 22 70 69 64 67 65 79
[1105] 22 2c 22 75 72 6c 22 3a 22 68 74 74 70 73 3a 2f 2f 70 6f 6b 65 61 70 69
[1129] 2e 63 6f 2f 61 70 69 2f 76 32 2f 70 6f 6b 65 6d 6f 6e 2f 31 36 2f 22 7d
[1153] 2c 7b 22 6e 61 6d 65 22 3a 22 70 69 64 67 65 6f 74 74 6f 22 2c 22 75 72
[1177] 6c 22 3a 22 68 74 74 70 73 3a 2f 2f 70 6f 6b 65 61 70 69 2e 63 6f 2f 61
[1201] 70 69 2f 76 32 2f 70 6f 6b 65 6d 6f 6e 2f 31 37 2f 22 7d 2c 7b 22 6e 61
[1225] 6d 65 22 3a 22 70 69 64 67 65 6f 74 22 2c 22 75 72 6c 22 3a 22 68 74 74
[1249] 70 73 3a 2f 2f 70 6f 6b 65 61 70 69 2e 63 6f 2f 61 70 69 2f 76 32 2f 70
[1273] 6f 6b 65 6d 6f 6e 2f 31 38 2f 22 7d 2c 7b 22 6e 61 6d 65 22 3a 22 72 61
[1297] 74 74 61 74 61 22 2c 22 75 72 6c 22 3a 22 68 74 74 70 73 3a 2f 2f 70 6f
[1321] 6b 65 61 70 69 2e 63 6f 2f 61 70 69 2f 76 32 2f 70 6f 6b 65 6d 6f 6e 2f
[1345] 31 39 2f 22 7d 2c 7b 22 6e 61 6d 65 22 3a 22 72 61 74 69 63 61 74 65 22
[1369] 2c 22 75 72 6c 22 3a 22 68 74 74 70 73 3a 2f 2f 70 6f 6b 65 61 70 69 2e
[1393] 63 6f 2f 61 70 69 2f 76 32 2f 70 6f 6b 65 6d 6f 6e 2f 32 30 2f 22 7d 5d
[1417] 7d

Parece que os dados ainda estão inacessíveis. Aqui, obtemos os dados binários do arquivo em formato hexadecimal.

Agora, vamos converter esses binários em string para ver o conteúdo do arquivo json.

pokemon_content <- httr::content(pokemon_call, as = "text")

pokemon_content
[1] "{\"count\":1302,\"next\":\"https://pokeapi.co/api/v2/pokemon/?offset=20&limit=20\",\"previous\":null,\"results\":[{\"name\":\"bulbasaur\",\"url\":\"https://pokeapi.co/api/v2/pokemon/1/\"},{\"name\":\"ivysaur\",\"url\":\"https://pokeapi.co/api/v2/pokemon/2/\"},{\"name\":\"venusaur\",\"url\":\"https://pokeapi.co/api/v2/pokemon/3/\"},{\"name\":\"charmander\",\"url\":\"https://pokeapi.co/api/v2/pokemon/4/\"},{\"name\":\"charmeleon\",\"url\":\"https://pokeapi.co/api/v2/pokemon/5/\"},{\"name\":\"charizard\",\"url\":\"https://pokeapi.co/api/v2/pokemon/6/\"},{\"name\":\"squirtle\",\"url\":\"https://pokeapi.co/api/v2/pokemon/7/\"},{\"name\":\"wartortle\",\"url\":\"https://pokeapi.co/api/v2/pokemon/8/\"},{\"name\":\"blastoise\",\"url\":\"https://pokeapi.co/api/v2/pokemon/9/\"},{\"name\":\"caterpie\",\"url\":\"https://pokeapi.co/api/v2/pokemon/10/\"},{\"name\":\"metapod\",\"url\":\"https://pokeapi.co/api/v2/pokemon/11/\"},{\"name\":\"butterfree\",\"url\":\"https://pokeapi.co/api/v2/pokemon/12/\"},{\"name\":\"weedle\",\"url\":\"https://pokeapi.co/api/v2/pokemon/13/\"},{\"name\":\"kakuna\",\"url\":\"https://pokeapi.co/api/v2/pokemon/14/\"},{\"name\":\"beedrill\",\"url\":\"https://pokeapi.co/api/v2/pokemon/15/\"},{\"name\":\"pidgey\",\"url\":\"https://pokeapi.co/api/v2/pokemon/16/\"},{\"name\":\"pidgeotto\",\"url\":\"https://pokeapi.co/api/v2/pokemon/17/\"},{\"name\":\"pidgeot\",\"url\":\"https://pokeapi.co/api/v2/pokemon/18/\"},{\"name\":\"rattata\",\"url\":\"https://pokeapi.co/api/v2/pokemon/19/\"},{\"name\":\"raticate\",\"url\":\"https://pokeapi.co/api/v2/pokemon/20/\"}]}"

Retorna os dados em formato de texto, mas ainda truncado.

Precisamos converter todo esse string json em uma tabela. Para isso, lançamos mão da função fromJSON() do pacote jsonlite.

pokemonJSON <- jsonlite::fromJSON(pokemon_content, flatten = TRUE)

pokemonJSON
$count
[1] 1302

$`next`
[1] "https://pokeapi.co/api/v2/pokemon/?offset=20&limit=20"

$previous
NULL

$results
         name                                   url
1   bulbasaur  https://pokeapi.co/api/v2/pokemon/1/
2     ivysaur  https://pokeapi.co/api/v2/pokemon/2/
3    venusaur  https://pokeapi.co/api/v2/pokemon/3/
4  charmander  https://pokeapi.co/api/v2/pokemon/4/
5  charmeleon  https://pokeapi.co/api/v2/pokemon/5/
6   charizard  https://pokeapi.co/api/v2/pokemon/6/
7    squirtle  https://pokeapi.co/api/v2/pokemon/7/
8   wartortle  https://pokeapi.co/api/v2/pokemon/8/
9   blastoise  https://pokeapi.co/api/v2/pokemon/9/
10   caterpie https://pokeapi.co/api/v2/pokemon/10/
11    metapod https://pokeapi.co/api/v2/pokemon/11/
12 butterfree https://pokeapi.co/api/v2/pokemon/12/
13     weedle https://pokeapi.co/api/v2/pokemon/13/
14     kakuna https://pokeapi.co/api/v2/pokemon/14/
15   beedrill https://pokeapi.co/api/v2/pokemon/15/
16     pidgey https://pokeapi.co/api/v2/pokemon/16/
17  pidgeotto https://pokeapi.co/api/v2/pokemon/17/
18    pidgeot https://pokeapi.co/api/v2/pokemon/18/
19    rattata https://pokeapi.co/api/v2/pokemon/19/
20   raticate https://pokeapi.co/api/v2/pokemon/20/

Se explorarmos qualquer um dos objetos pokemonJSON, notaremos que o que nos interessa está localizado dentro de results.

pokemonJSON$results
         name                                   url
1   bulbasaur  https://pokeapi.co/api/v2/pokemon/1/
2     ivysaur  https://pokeapi.co/api/v2/pokemon/2/
3    venusaur  https://pokeapi.co/api/v2/pokemon/3/
4  charmander  https://pokeapi.co/api/v2/pokemon/4/
5  charmeleon  https://pokeapi.co/api/v2/pokemon/5/
6   charizard  https://pokeapi.co/api/v2/pokemon/6/
7    squirtle  https://pokeapi.co/api/v2/pokemon/7/
8   wartortle  https://pokeapi.co/api/v2/pokemon/8/
9   blastoise  https://pokeapi.co/api/v2/pokemon/9/
10   caterpie https://pokeapi.co/api/v2/pokemon/10/
11    metapod https://pokeapi.co/api/v2/pokemon/11/
12 butterfree https://pokeapi.co/api/v2/pokemon/12/
13     weedle https://pokeapi.co/api/v2/pokemon/13/
14     kakuna https://pokeapi.co/api/v2/pokemon/14/
15   beedrill https://pokeapi.co/api/v2/pokemon/15/
16     pidgey https://pokeapi.co/api/v2/pokemon/16/
17  pidgeotto https://pokeapi.co/api/v2/pokemon/17/
18    pidgeot https://pokeapi.co/api/v2/pokemon/18/
19    rattata https://pokeapi.co/api/v2/pokemon/19/
20   raticate https://pokeapi.co/api/v2/pokemon/20/

Acessar os dados de cada pokémon

Uma maneira seria alterar a URL base, adicionando endpoints:

pokemon_url <- "https://pokeapi.co/api/v2/pokemon/{endpoint}"

Nesse sentido, separar a base do URL dos endpoints é muito conveniente.

Por exemplo, podemos usar essa API para obtermos os stats do Growlithe:

pokemon_base <- "https://pokeapi.co/api/v2/pokemon/"

growlithe_endpoint <- "58"

growlithe_url <- base::paste0(pokemon_base, growlithe_endpoint)

growlithe_call <- httr::GET(growlithe_url)

growlithe_content <- httr::content(growlithe_call, as = "text")

growlithe_JSON <- jsonlite::fromJSON(growlithe_content, flatten = TRUE)

growlithe_stats <- data.frame(growlithe_JSON$stats)

growlithe_stats

  base_stat effort       stat.name                          stat.url
1        55      0              hp https://pokeapi.co/api/v2/stat/1/
2        70      1          attack https://pokeapi.co/api/v2/stat/2/
3        45      0         defense https://pokeapi.co/api/v2/stat/3/
4        70      0  special-attack https://pokeapi.co/api/v2/stat/4/
5        50      0 special-defense https://pokeapi.co/api/v2/stat/5/
6        60      0           speed https://pokeapi.co/api/v2/stat/6/

Aplicações

https://pokemoncries.com/

API OpenWeather

Site com várias API’s públicas

Referências